2 * Copyright (c) 2002-2003 Apple Computer, Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
21 * @APPLE_LICENSE_HEADER_END@
23 Change History (most recent first):
25 $Log: Mac\040OS\040Test\040Searcher.c,v $
26 Revision 1.20 2004/10/19 21:33:18 cheshire
27 <rdar://problem/3844991> Cannot resolve non-local registrations using the mach API
28 Added flag 'kDNSServiceFlagsForceMulticast'. Passing through an interface id for a unicast name
29 doesn't force multicast unless you set this flag to indicate explicitly that this is what you want
31 Revision 1.19 2004/09/17 01:08:50 cheshire
32 Renamed mDNSClientAPI.h to mDNSEmbeddedAPI.h
33 The name "mDNSClientAPI.h" is misleading to new developers looking at this code. The interfaces
34 declared in that file are ONLY appropriate to single-address-space embedded applications.
35 For clients on general-purpose computers, the interfaces defined in dns_sd.h should be used.
37 Revision 1.18 2004/09/16 21:59:16 cheshire
38 For consistency with zerov6Addr, rename zeroIPAddr to zerov4Addr
40 Revision 1.17 2004/06/10 04:37:27 cheshire
41 Add new parameter in mDNS_GetDomains()
43 Revision 1.16 2004/03/12 21:30:25 cheshire
44 Build a System-Context Shared Library from mDNSCore, for the benefit of developers
45 like Muse Research who want to be able to use mDNS/DNS-SD from GPL-licensed code.
47 Revision 1.15 2004/01/24 23:55:15 cheshire
48 Change to use mDNSOpaque16fromIntVal/mDNSVal16 instead of shifting and masking
50 Revision 1.14 2003/11/14 21:27:09 cheshire
51 <rdar://problem/3484766>: Security: Crashing bug in mDNSResponder
52 Fix code that should use buffer size MAX_ESCAPED_DOMAIN_NAME (1005) instead of 256-byte buffers.
54 Revision 1.13 2003/08/14 02:19:54 cheshire
55 <rdar://problem/3375491> Split generic ResourceRecord type into two separate types: AuthRecord and CacheRecord
57 Revision 1.12 2003/08/12 19:56:24 cheshire
62 #include <stdio.h> // For printf()
63 #include <Events.h> // For WaitNextEvent()
64 #include <SIOUX.h> // For SIOUXHandleOneEvent()
66 #include "mDNSEmbeddedAPI.h" // Defines the interface to the client layer above
67 #include "mDNSMacOS9.h" // Defines the specific types needed to run mDNS on this platform
71 OTLIFO serviceinfolist
;
72 Boolean headerPrinted
;
76 typedef struct { ServiceInfo i
; mDNSBool add
; mDNSBool dom
; OTLink link
; } linkedServiceInfo
;
78 // These don't have to be globals, but their memory does need to remain valid for as
79 // long as the search is going on. They are declared as globals here for simplicity.
80 #define RR_CACHE_SIZE 1000
81 static CacheRecord rrcachestorage
[RR_CACHE_SIZE
];
82 static mDNS mDNSStorage
;
83 static mDNS_PlatformSupport PlatformSupportStorage
;
84 static SearcherServices services
;
85 static DNSQuestion browsequestion
, domainquestion
;
87 // PrintServiceInfo prints the service information to standard out
88 // A real application might want to do something else with the information
89 static void PrintServiceInfo(SearcherServices
*services
)
91 OTLink
*link
= OTReverseList(OTLIFOStealList(&services
->serviceinfolist
));
95 linkedServiceInfo
*ls
= OTGetLinkObject(link
, linkedServiceInfo
, link
);
96 ServiceInfo
*s
= &ls
->i
;
98 if (!services
->headerPrinted
)
100 printf("%-55s Type Domain IP Address Port Info\n", "Name");
101 services
->headerPrinted
= true;
106 char c_dom
[MAX_ESCAPED_DOMAIN_NAME
];
107 ConvertDomainNameToCString(&s
->name
, c_dom
);
108 if (ls
->add
) printf("%-55s available for browsing\n", c_dom
);
109 else printf("%-55s no longer available for browsing\n", c_dom
);
114 domainname type
, domain
;
115 char c_name
[MAX_DOMAIN_LABEL
+1], c_type
[MAX_ESCAPED_DOMAIN_NAME
], c_dom
[MAX_ESCAPED_DOMAIN_NAME
], c_ip
[20];
116 DeconstructServiceName(&s
->name
, &name
, &type
, &domain
);
117 ConvertDomainLabelToCString_unescaped(&name
, c_name
);
118 ConvertDomainNameToCString(&type
, c_type
);
119 ConvertDomainNameToCString(&domain
, c_dom
);
120 sprintf(c_ip
, "%d.%d.%d.%d", s
->ip
.ip
.v4
.b
[0], s
->ip
.ip
.v4
.b
[1], s
->ip
.ip
.v4
.b
[2], s
->ip
.ip
.v4
.b
[3]);
122 printf("%-55s %-16s %-14s ", c_name
, c_type
, c_dom
);
123 if (ls
->add
) printf("%-15s %5d %#s\n", c_ip
, mDNSVal16(s
->port
), s
->TXTinfo
);
124 else printf("Removed\n");
132 // When the name, address, port, and txtinfo for a service is found, FoundInstanceInfo()
133 // enqueues a record for PrintServiceInfo() to print.
134 // Note, a browsing application would *not* normally need to get all this information --
135 // all it needs is the name, to display to the user.
136 // Finding out the address, port, and txtinfo should be deferred to the time that the user
137 // actually needs to contact the service to use it.
138 static void FoundInstanceInfo(mDNS
*const m
, ServiceInfoQuery
*query
)
140 SearcherServices
*services
= (SearcherServices
*)query
->ServiceInfoQueryContext
;
141 linkedServiceInfo
*info
= (linkedServiceInfo
*)(query
->info
);
142 if (query
->info
->ip
.type
== mDNSAddrType_IPv4
)
144 mDNS_StopResolveService(m
, query
); // For this test code, one answer is sufficient
145 OTLIFOEnqueue(&services
->serviceinfolist
, &info
->link
);
150 // When a new named instance of a service is found, FoundInstance() is called.
151 // In this sample code we turn around and immediately issue a query to resolve that service name to
152 // find its address, port, and txtinfo, but a normal browing application would just display the name.
153 static void FoundInstance(mDNS
*const m
, DNSQuestion
*question
, const ResourceRecord
*const answer
, mDNSBool AddRecord
)
155 #pragma unused (question)
156 SearcherServices
*services
= (SearcherServices
*)question
->QuestionContext
;
157 linkedServiceInfo
*info
;
159 debugf("FoundInstance %##s PTR %##s", answer
->name
.c
, answer
->rdata
->u
.name
.c
);
161 if (answer
->rrtype
!= kDNSType_PTR
) return;
162 if (!services
) { debugf("FoundInstance: services is NULL"); return; }
164 info
= (linkedServiceInfo
*)OTAllocMem(sizeof(linkedServiceInfo
));
165 if (!info
) { services
->lostRecords
= true; return; }
167 info
->i
.name
= answer
->rdata
->u
.name
;
168 info
->i
.InterfaceID
= answer
->InterfaceID
;
169 info
->i
.ip
.type
= mDNSAddrType_IPv4
;
170 info
->i
.ip
.ip
.v4
= zerov4Addr
;
171 info
->i
.port
= zeroIPPort
;
172 info
->add
= AddRecord
;
173 info
->dom
= mDNSfalse
;
175 if (!AddRecord
) // If TTL == 0 we're deleting a service,
176 OTLIFOEnqueue(&services
->serviceinfolist
, &info
->link
);
177 else // else we're adding a new service
179 ServiceInfoQuery
*q
= (ServiceInfoQuery
*)OTAllocMem(sizeof(ServiceInfoQuery
));
180 if (!q
) { OTFreeMem(info
); services
->lostRecords
= true; return; }
181 mDNS_StartResolveService(m
, q
, &info
->i
, FoundInstanceInfo
, services
);
185 static void FoundDomain(mDNS
*const m
, DNSQuestion
*question
, const ResourceRecord
*const answer
, mDNSBool AddRecord
)
188 #pragma unused (question)
189 SearcherServices
*services
= (SearcherServices
*)question
->QuestionContext
;
190 linkedServiceInfo
*info
;
192 debugf("FoundDomain %##s PTR %##s", answer
->name
.c
, answer
->rdata
->u
.name
.c
);
194 if (answer
->rrtype
!= kDNSType_PTR
) return;
195 if (!services
) { debugf("FoundDomain: services is NULL"); return; }
197 info
= (linkedServiceInfo
*)OTAllocMem(sizeof(linkedServiceInfo
));
198 if (!info
) { services
->lostRecords
= true; return; }
200 info
->i
.name
= answer
->rdata
->u
.name
;
201 info
->i
.InterfaceID
= answer
->InterfaceID
;
202 info
->i
.ip
.type
= mDNSAddrType_IPv4
;
203 info
->i
.ip
.ip
.v4
= zerov4Addr
;
204 info
->i
.port
= zeroIPPort
;
205 info
->add
= AddRecord
;
206 info
->dom
= mDNStrue
;
208 OTLIFOEnqueue(&services
->serviceinfolist
, &info
->link
);
211 // YieldSomeTime() just cooperatively yields some time to other processes running on classic Mac OS
212 static Boolean
YieldSomeTime(UInt32 milliseconds
)
214 extern Boolean SIOUXQuitting
;
216 WaitNextEvent(everyEvent
, &e
, milliseconds
/ 17, NULL
);
217 SIOUXHandleOneEvent(&e
);
218 return(SIOUXQuitting
);
224 Boolean DoneSetup
= false;
227 SIOUXSettings
.asktosaveonclose
= false;
228 SIOUXSettings
.userwindowtitle
= "\pMulticast DNS Searcher";
229 SIOUXSettings
.rows
= 40;
230 SIOUXSettings
.columns
= 132;
232 printf("Multicast DNS Searcher\n\n");
233 printf("This software reports errors using MacsBug breaks,\n");
234 printf("so if you don't have MacsBug installed your Mac may crash.\n\n");
235 printf("******************************************************************************\n");
237 err
= InitOpenTransport();
238 if (err
) { debugf("InitOpenTransport failed %d", err
); return(err
); }
240 err
= mDNS_Init(&mDNSStorage
, &PlatformSupportStorage
, rrcachestorage
, RR_CACHE_SIZE
,
241 mDNS_Init_DontAdvertiseLocalAddresses
, mDNS_Init_NoInitCallback
, mDNS_Init_NoInitCallbackContext
);
242 if (err
) return(err
);
244 // Make sure OT has a large enough memory pool for us to draw from at OTNotifier (interrupt) time
245 tempmem
= OTAllocMem(0x10000);
246 if (tempmem
) OTFreeMem(tempmem
);
247 else printf("**** Warning: OTAllocMem couldn't pre-allocate 64K for us.\n");
249 services
.serviceinfolist
.fHead
= NULL
;
250 services
.headerPrinted
= false;
251 services
.lostRecords
= false;
253 while (!YieldSomeTime(35))
255 #if MDNS_ONLYSYSTEMTASK
256 // For debugging, use "#define MDNS_ONLYSYSTEMTASK 1" and call mDNSPlatformIdle() periodically.
257 // For shipping code, don't define MDNS_ONLYSYSTEMTASK, and you don't need to call mDNSPlatformIdle()
258 extern void mDNSPlatformIdle(mDNS
*const m
);
259 mDNSPlatformIdle(&mDNSStorage
); // Only needed for debugging version
261 if (mDNSStorage
.mDNSPlatformStatus
== mStatus_NoError
&& !DoneSetup
)
263 domainname srvtype
, srvdom
;
265 printf("\nSending mDNS service lookup queries and waiting for responses...\n\n");
266 MakeDomainNameFromDNSNameString(&srvtype
, "_http._tcp.");
267 MakeDomainNameFromDNSNameString(&srvdom
, "local.");
268 err
= mDNS_StartBrowse(&mDNSStorage
, &browsequestion
, &srvtype
, &srvdom
, mDNSInterface_Any
, mDNSfalse
, FoundInstance
, &services
);
270 err
= mDNS_GetDomains(&mDNSStorage
, &domainquestion
, mDNS_DomainTypeBrowse
, NULL
, mDNSInterface_Any
, FoundDomain
, &services
);
274 if (services
.serviceinfolist
.fHead
)
275 PrintServiceInfo(&services
);
277 if (services
.lostRecords
)
279 services
.lostRecords
= false;
280 printf("**** Warning: Out of memory: Records have been missed.\n");
284 mDNS_StopBrowse(&mDNSStorage
, &browsequestion
);
285 mDNS_Close(&mDNSStorage
);